package com.larsgard.gedviewer.server.services;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.logging.Logger;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.larsgard.gedviewer.client.service.UserDataService;
import com.larsgard.gedviewer.server.ged.GenjGedParser;
import com.larsgard.gedviewer.server.storage.FeedbackStorage;
import com.larsgard.gedviewer.server.storage.GedFile;
import com.larsgard.gedviewer.server.storage.GedFileStorage;
import com.larsgard.gedviewer.server.storage.PersonStorage;
import com.larsgard.gedviewer.server.storage.TreeStorage;
import com.larsgard.gedviewer.server.storage.entities.JDOFeedback;
import com.larsgard.gedviewer.server.storage.entities.JDOPerson;
import com.larsgard.gedviewer.server.storage.entities.JDOUserTree;
import com.larsgard.gedviewer.shared.Feedback;
import com.larsgard.gedviewer.shared.ListUserTreesResult;
import com.larsgard.gedviewer.shared.ProcessRequest;
import com.larsgard.gedviewer.shared.ProcessResult;
import com.larsgard.gedviewer.shared.ProcessRequest.OPERATION;
import com.larsgard.gedviewer.shared.entities.UserTree;

@RemoteServiceRelativePath("initializedata")
public class UserDataServiceImpl extends RemoteServiceServlet implements UserDataService {

    static final Logger log = Logger.getLogger(UserDataServiceImpl.class.getName());

    private static final long serialVersionUID = 4764548677434315060L;

    private static TreeStorage treeStorage = TreeStorage.getInstance();

    @Override
    public ListUserTreesResult getUserTrees() {
	ListUserTreesResult result = new ListUserTreesResult();
	UserService userService = UserServiceFactory.getUserService();
	User user = userService.getCurrentUser();
	if (user != null) {
	    ArrayList<JDOUserTree> treesForUser = treeStorage.getTreesForUser(user.getEmail());
	    UserTree[] trees = new UserTree[treesForUser.size()];
	    for (int i = 0; i < trees.length; i++) {
		trees[i] = treesForUser.get(i).getUserTree();
	    }
	    result.setTrees(trees);
	}
	return result;
    }

    @Override
    public ProcessResult processGedFile(ProcessRequest request) throws IOException {
	if (request.getOperation() == OPERATION.PROCESS_GED) {
	    return processGed(request);
	} else if (request.getOperation() == OPERATION.DELETE) {
	    return deleteTree(request);
	}
	return null;
    }

    private ProcessResult deleteTree(ProcessRequest request) {
	GedFile gedFile = GedFileStorage.getInstance().getFile(request.getFileKey());

	PersonStorage.getInstance().deleteAllWithTreeId(gedFile.getTreeId());
	TreeStorage.getInstance().deleteTree(gedFile.getFileId());
	GedFileStorage.getInstance().deleteFile(gedFile);
	ProcessResult result = new ProcessResult();
	result.setFinished(true);
	return result;
    }

    private ProcessResult processGed(ProcessRequest request) throws IOException {
	final Long start = System.currentTimeMillis();

	ProcessResult result = new ProcessResult();

	GedFile gedFile = GedFileStorage.getInstance().getFile(request.getFileKey());
	JDOUserTree tree = treeStorage.getTreesWithFileKey(request.getFileKey());

	String fileContent = gedFile.getGedFile().getValue();
	InputStream in = new ByteArrayInputStream(fileContent.getBytes());

	GenjGedParser parser = new GenjGedParser(in);
	parser.skip(request.getSkipCount());

	while (parser.hasNext()) {
	    if ((System.currentTimeMillis() - start) > 28000) {
		break;

	    }

	    JDOPerson next = parser.next();
	    next.setTreeId(tree.getTreeId());
	    next.setKey(PersonStorage.getInstance().createKey(next, next.getIdno(), tree.getKey()));
	    PersonStorage.getInstance().persistPerson(next);
	}

	if (!parser.hasNext()) {
	    tree.setProcessed(true);
	    treeStorage.updateTreeProcessed(tree);
	}
	result.setPosition(parser.getRead());
	result.setFinished(!parser.hasNext());
	result.setOperation(request.getOperation());
	result.setFileId(request.getFileKey());
	result.setTotal(parser.getCount());
	return result;
    }

    @Override
    public void sendFeedBack(Feedback feedback) {
	UserService userService = UserServiceFactory.getUserService();
	User user = userService.getCurrentUser();
	JDOFeedback jdoFeedback = JDOFeedback.fromFeedBack(feedback);
	if (user != null) {
	    jdoFeedback.setFrom(user.getEmail());
	}
	new FeedbackStorage().persistFeedback(jdoFeedback);
    }
}
